<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>EventBus2-4-0源码分析之订阅 | 清风向阳</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  
    <meta name="keywords" content="Joker,Joker's Blog" />
  
  <meta name="description" content="EventBus最新的版本是3.0了但是beta版，所有我们还是按2.4分析源码是如何工作的，EventBus是一个简化Activities, Fragments, Threads, Services等等直接通信的框架。GitHub上的原文：Android optimized event bus that simplifies communication between Activities,">
<meta name="keywords" content="Rxjava">
<meta property="og:type" content="article">
<meta property="og:title" content="EventBus2-4-0源码分析之订阅">
<meta property="og:url" content="http://mjjde.github.io/2015/12/23/EventBus2-4-0源码分析之订阅/index.html">
<meta property="og:site_name" content="清风向阳">
<meta property="og:description" content="EventBus最新的版本是3.0了但是beta版，所有我们还是按2.4分析源码是如何工作的，EventBus是一个简化Activities, Fragments, Threads, Services等等直接通信的框架。GitHub上的原文：Android optimized event bus that simplifies communication between Activities,">
<meta property="og:image" content="http://jokero1o.github.io/images/EventBus-Publish-Subscribe.png">
<meta property="og:updated_time" content="2017-09-15T07:00:26.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="EventBus2-4-0源码分析之订阅">
<meta name="twitter:description" content="EventBus最新的版本是3.0了但是beta版，所有我们还是按2.4分析源码是如何工作的，EventBus是一个简化Activities, Fragments, Threads, Services等等直接通信的框架。GitHub上的原文：Android optimized event bus that simplifies communication between Activities,">
<meta name="twitter:image" content="http://jokero1o.github.io/images/EventBus-Publish-Subscribe.png">
  
  
    <link rel="icon" href="/favicon_pic.ico">
  
  <link href="//cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css">
  <script src="/js/pace.min.js"></script>
  

  
  

</head>

<body>
  <div id="container">
      <header id="header">
    <div id="banner"></div>
    <div id="header-outer">
        <div id="header-menu" class="header-menu-pos animated">
            <div class="header-menu-container">
                <a href="/" class="left">
                    <span class="site-title">Joker&#39;s Blog</span>
                </a>
                <nav id="header-menu-nav" class="right">
                    
                    <a  href="/">
                        <i class="fa fa-home"></i>
                        <span>Home</span>
                    </a>
                    
                    <a  href="/archives">
                        <i class="fa fa-archive"></i>
                        <span>Archives</span>
                    </a>
                    
                    <a  href="/about">
                        <i class="fa fa-user"></i>
                        <span>About</span>
                    </a>
                    
                </nav>
                <a class="mobile-header-menu-button">
                    <i class="fa fa-bars"></i>
                </a>
            </div>
        </div>
        <div id="header-row">
            <div id="logo">
                <a href="/">
                    <img src="/images/avatar.jpg" alt="logo">
                </a>
            </div>
            <div class="header-info">
                <div id="header-title">
                    
                    <h2>
                        Joker&#39;s Blog
                    </h2>
                    
                </div>
                <div id="header-description">
                    
                    <h3>
                        一个认真的技术博客
                    </h3>
                    
                </div>
            </div>
            <nav class="header-nav">
                <div class="social">
                    
                        <a title="Joker"  href="//joker-studio.pub">
                            <i class="fa fa-home fa-2x"></i></a>
                    
                        <a title="Github" target="_blank" href="//github.com/mjjde">
                            <i class="fa fa-github fa-2x"></i></a>
                    
                </div>
            </nav>
        </div>
    </div>
</header>
      <div class="outer">
        <section id="main" class="body-wrap"><article id="post-EventBus2-4-0源码分析之订阅" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-inner">
    
      <header class="article-header">
        
  
    <h1 class="post-title" itemprop="name">
      EventBus2-4-0源码分析之订阅
    </h1>
    <div class="post-title-bar">
      <ul>
          
              <li>
                  <i class="fa fa-book"></i>
                  
                      <a href="/categories/Android技术/">Android技术</a>
                  
              </li>
          
        <li>
          <i class="fa fa-calendar"></i>  2015-12-23
        </li>
        <li>
          <i class="fa fa-eye"></i>
          <span id="busuanzi_value_page_pv"></span>
        </li>
      </ul>
    </div>
  

          
      </header>
    
    <div class="article-entry post-content" itemprop="articleBody">
      
            
            <blockquote>
<p>EventBus最新的版本是3.0了但是beta版，所有我们还是按2.4分析源码是如何工作的，EventBus是一个简化Activities, Fragments, Threads, Services等等直接通信的框架。GitHub上的原文：Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality。<br><a id="more"></a><br>在GitHub地址<a href="https://github.com/greenrobot/EventBus" target="_blank" rel="external">在这里</a>该作者也是另一个开源greenDAO的作者，棒棒哒。我们以前的通信机制基本基于Handler，Bunder来进行的，现在我们使用EventBus会给我们带来很大的便捷。接下来我们先来了解下EventBus的使用。</p>
</blockquote>
<ol>
<li>导入EventBus，可以在Gradle：compile ‘de.greenrobot:eventbus:2.4.0’，也可以下载jar包导入。</li>
<li>定义事件：public class MessageEvent { / <em>Additional fields if needed</em> / }</li>
<li>注册订阅者： eventBus.register(this); public void onEvent(AnyEventType event) {/ <em>Do something</em> /};订阅者的方法可以是onEvent，onEventMainThread,onEventBackgroundThread,onEventAsync,分别对应了不同的ThreadMode</li>
<li>发送事件：eventBus.post(event);</li>
</ol>
<p>流程很简单这样我们就可以进行事件的发送和接收了。我们已经知道如何简单的使用的，现在来看看EventBus的源码。</p>
<p><img src="http://jokero1o.github.io/images/EventBus-Publish-Subscribe.png" alt=""><br>从图中我们可以看到，整个事件的订阅和发送都和EventBus有关，这篇将介绍订阅部分，我们的入口是Eventbus这个类。</p>
<h4 id="EventBus-java"><a href="#EventBus-java" class="headerlink" title="EventBus.java"></a><a href="#EventBus-java" title="EventBus.java"></a>EventBus.java</h4><p><a href="https://github.com/greenrobot/EventBus/blob/master/EventBus/src/de/greenrobot/event/EventBus.java" target="_blank" rel="external">Github For EventBus.java</a></p>
<p>我们先来看下EventBus获取实例的两个方法</p>
<ol>
<li>默认的构造，getDefault()正常的单例模式。在构造方法里我们看到了使用了一个默认的EventBusBuilder来构建的。</li>
<li>那么还有一种就是自己定义EventBusBuilder，来生成一个EventBus,我们可以看到在EventBusBuilder有个方法</li>
</ol>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">public</span> <span class="function">EventBus <span class="title">installDefaultEventBus</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">synchronized</span> (EventBus.class) &#123;</div><div class="line">    <span class="keyword">if</span> (EventBus.defaultInstance != <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> EventBusException(<span class="string">"Default instance already exists."</span> +</div><div class="line">                <span class="string">" It may be only set once before it's used the first time to ensure consistent behavior."</span>);</div><div class="line">    &#125;</div><div class="line">    EventBus.defaultInstance = build();</div><div class="line">        <span class="keyword">return</span> EventBus.defaultInstance;</div><div class="line">        &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>在这个方法里面有个判断，如果EventBus已经存在实例了，那么就会抛出异常。为什么呢，我们下面在来说。</p>
<p>两种方式都介绍过了，我们一般使用第一种默认的就已经足够了。</p>
<p>在来看EventBus的register方法，虽然都多个但是最后调用的都是一个 <em>private synchronized void register(Object subscriber, boolean sticky, int priority)</em> 这个方法是用来注册订阅者的,参数subscriber就是订阅者，如果是在Activity中注册的话那就是Activity，sticky为true的话就可以跨界面进行通信，跟广播类似，为false，就是在单个订阅者进行通信，这两种还是有很大的区别的，我们下面会分析。看下具体的实现。</p>
<p>List <subscribermethod>subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());</subscribermethod></p>
<p>该方法调用的subscriberMethodFinder的方法。我们来看下SubscriberMethodFinder，根据类名我们就大致了解是干嘛的了，他是查找订阅者中订阅的方法的，使用的是反射机制。对于反射来说也是有缺点的，那就是会消耗一部分的时间来完成，那么SubscriberMethodFinder类采用了缓存机制来保证不会重复的做反射耗时操作， <em>Map<class<?>, List<subscribermethod>&gt; methodCache</subscribermethod></class<?></em> 该变量以订阅者Class为key ,SubscriberMethod集合为value的map集合，那么SubscriberMethod类里面保存的是什么呢。</p>
<figure class="highlight oxygene"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">    SubscriberMethod(<span class="function"><span class="keyword">Method</span> <span class="title">method</span>, <span class="title">ThreadMode</span> <span class="title">threadMode</span>, <span class="title">Class</span>&lt;?&gt; <span class="title">eventType</span>) <span class="comment">&#123;</span></span></div><div class="line">    this.method = method;</div><div class="line">    this.threadMode = threadMode;</div><div class="line">    this.eventType = eventType;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>保存的是方法相关的信息，1.方法对象。2.ThreadMode线程模式这个我们后面会说到。3.参数类型Class.<br>这样就能描述一个订阅方法的所需信息了。</p>
<p>subscriberMethodFinder方法首先会去查找缓存，如果没有那么就反射获取SubscriberMethod的信息。这个方法里做得另一个优化就是判断订阅者是否是java.，javax，android.开始的类，如果不是才会做接下来的事情。然后反射出所有得方法。调用<em>filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods)</em> 。看名字也知道这个方法是用来筛选符合的Method。</p>
<p>filterSubscriberMethods方法首先遍历methods，判断方法名是否是onEvent开头的，过滤掉Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC方法修饰符，过滤掉方法参数不是一个的。然后将剩下的符合条件的方法用methodName&gt;参数类型为Key,SubscriberMethod对象为value，保存到缓存内。</p>
<p>我们在subscriberMethodFinder看到有个clazz = clazz.getSuperclass();这样的话我们发现不止是在本对象中找符合条件的onEvent方法，还会在其父类里找，这里有个点就是如果子类覆写了父类的onEvent方法，那么会屏蔽掉父类的onEvent。</p>
<p>上面的方法统计完该类和其父类的符合条件的onEvent方法后，在从register方法往下看。它接着会遍历我们查找到得SubscriberMethod集合，并调用 <em>subscribe(subscriber, subscriberMethod, sticky, priority)</em> 方法。</p>
<p>接下来我们来看这个方法做了什么。首先根据订阅方法的参数类型查看是否已经存在对应的Subscription集合。Subscription中保存的是什么，我们来看下构造方法</p>
<figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">    <span class="keyword">Subscription(Object </span><span class="keyword">subscriber, </span><span class="keyword">SubscriberMethod </span><span class="keyword">subscriberMethod, </span>int priority) &#123;</div><div class="line">    this.<span class="keyword">subscriber </span>= <span class="keyword">subscriber;</span></div><div class="line">    this.<span class="keyword">subscriberMethod </span>= <span class="keyword">subscriberMethod;</span></div><div class="line">    this.priority = priority<span class="comment">;</span></div><div class="line">    active = true<span class="comment">;</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>保存了订阅者对象，订阅方法对象，权重。<br>如果不存在对应的Subscription集合那么就创建一个，如果有在判断集合里是否有一样的Subscription，是这抛出异常，不能重复监听同个事件。否，就按照权重将新建的Subscription加入到集合里保存下来。用于Post的时候发起调用。</p>
<p>接下来又是一个集合，以订阅者subscriber为Key,订阅事件的参数类型为value，这个是用来取消注册时用的。</p>
<p>我们接下来看到的是sticky的注册，判断是否允许事件影响到其父类，接口等上层类，然后调用<em>checkPostStickyEventToSubscription(newSubscription, stickyEvent);</em> 这个方法调用 <em>postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());</em> 这个方法会触发事件的调用分发，这里我们可以看到普通的register和sticky register的区别，普通的注册是没有立刻去触发事件，而是在post的时候才触发，但是sticky register刚好相反，是字注册的时候去触发事件的。事件都会保存在stickyEvents中。当然对于sticky的post也会理解触发事件，这是兼容了普通的事件注册。</p>
<p>这篇文章介绍完了。相信对EventBus的事件注册有一定的了解了。下篇我们将分析EventBus的Post发送事件。</p>

            <div class="post-copyright">
    <div class="content">
        <p>最后更新： 2017年09月15日 15:00</p>
        <p>原始链接： <a class="post-url" href="/2015/12/23/EventBus2-4-0源码分析之订阅/" title="EventBus2-4-0源码分析之订阅">http://mjjde.github.io/2015/12/23/EventBus2-4-0源码分析之订阅/</a></p>
        <footer>
            <a href="http://mjjde.github.io">
                <img src="/images/avatar.jpg" alt="Joker Mei">
                Joker Mei
            </a>
        </footer>
    </div>
</div>

      
    </div>
    <footer class="article-footer">
        
        
<div class="post-share">
    <a href="javascript:;" id="share-sub" class="post-share-fab">
        <i class="fa fa-share-alt"></i>
    </a>
    <div class="post-share-list" id="share-list">
        <ul class="share-icons">
          <li>
            <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://mjjde.github.io/2015/12/23/EventBus2-4-0源码分析之订阅/&title=《EventBus2-4-0源码分析之订阅》 — 清风向阳&pic=http://mjjde.github.ioimages/avatar.jpg" data-title="微博">
              <i class="fa fa-weibo"></i>
            </a>
          </li>
          <li>
            <a class="weixin share-sns" id="wxFab" href="javascript:;" data-title="微信">
              <i class="fa fa-weixin"></i>
            </a>
          </li>
          <li>
            <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://mjjde.github.io/2015/12/23/EventBus2-4-0源码分析之订阅/&title=《EventBus2-4-0源码分析之订阅》 — 清风向阳&source=
EventBus最新的版本是3.0了但是beta版，所有我们还是按2.4分析源码是如何工作的，EventBus是一个简化Activities, Frag..." data-title="QQ">
              <i class="fa fa-qq"></i>
            </a>
          </li>
          <li>
            <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://mjjde.github.io/2015/12/23/EventBus2-4-0源码分析之订阅/" data-title="Facebook">
              <i class="fa fa-facebook"></i>
            </a>
          </li>
          <li>
            <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《EventBus2-4-0源码分析之订阅》 — 清风向阳&url=http://mjjde.github.io/2015/12/23/EventBus2-4-0源码分析之订阅/&via=http://mjjde.github.io" data-title="Twitter">
              <i class="fa fa-twitter"></i>
            </a>
          </li>
          <li>
            <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://mjjde.github.io/2015/12/23/EventBus2-4-0源码分析之订阅/" data-title="Google+">
              <i class="fa fa-google-plus"></i>
            </a>
          </li>
        </ul>
     </div>
</div>
<div class="post-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;" id="wxShare-close">×</a>
    <p>扫一扫，分享到微信</p>
    <img src="//api.qrserver.com/v1/create-qr-code/?data=http://mjjde.github.io/2015/12/23/EventBus2-4-0源码分析之订阅/" alt="微信分享二维码">
</div>

<div class="mask"></div>

        
        <ul class="article-footer-menu">
            
            
  <li class="article-footer-tags">
    <i class="fa fa-tags"></i>
      
    <a href="/tags/Rxjava/" class="color2">Rxjava</a>
      
  </li>

        </ul>
        
    </footer>
  </div>
</article>


    <aside class="post-toc-pos post-toc-top" id="post-toc">
        <nav class="post-toc-wrap">
            <ol class="post-toc"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#EventBus-java"><span class="post-toc-text">EventBus.java</span></a></li></ol>
        </nav>
    </aside>
    

<nav id="article-nav">
  
    <a href="/2015/12/25/EventBus2-4-0源码分析之Post/" id="article-nav-newer" class="article-nav-link-wrap">

      <span class="article-nav-title">
        <i class="fa fa-hand-o-left" aria-hidden="true"></i>
        
          EventBus2-4-0源码分析之Post
        
      </span>
    </a>
  
  
    <a href="/2015/12/14/Rxjava-简化你的异步调用/" id="article-nav-older" class="article-nav-link-wrap">
      <span class="article-nav-title">Rxjava-简化你的异步调用</span>
      <i class="fa fa-hand-o-right" aria-hidden="true"></i>
    </a>
  
</nav>



    
</section>
        
      </div>
      <footer id="footer">
  <div class="outer">
    <div id="footer-info" class="inner">
      
<p>
    <span id="busuanzi_container_site_uv" style='display:none'>
        总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style='display:none'>
        总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


      <p>
        Powered by  <a href="http://hexo.io/" target="_blank">Hexo</a>
        Theme <a href="//github.com/wongminho/hexo-theme-miho" target="_blank">MiHo</a>
      &copy; 2018 Joker Mei<br>
      </p>
    </div>
  </div>
</footer>
    <script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<script src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script>
  var mihoConfig = {
      root: "http://mjjde.github.io",
      animate: false,
      isHome: false,
      share: true
  }
</script>
<div class="sidebar">
    <!-- <div id="sidebar-search" title="Search">
        <i class="fa fa-search"></i>
    </div> -->
    <div id="sidebar-category" title="Categories">
        <i class="fa fa-book"></i>
    </div>
    <div id="sidebar-tag" title="Tags">
        <i class="fa fa-tags"></i>
    </div>
    <div id="sidebar-top">
        <span class="sidebar-top-icon"><i class="fa fa-angle-up"></i></span>
    </div>
</div>
<div class="sidebar-menu-box" id="sidebar-menu-box">
    <div class="sidebar-menu-box-container">
        <div id="sidebar-menu-box-categories">
            <a class="category-link" href="/categories/Android技术/">Android技术</a><a class="category-link" href="/categories/其他技术/">其他技术</a><a class="category-link" href="/categories/网络技术/">网络技术</a><a class="category-link" href="/categories/设计模式/">设计模式</a>
        </div>
        <div id="sidebar-menu-box-tags">
            <a href="/tags/Activity/" style="font-size: 10px;">Activity</a> <a href="/tags/Android/" style="font-size: 16px;">Android</a> <a href="/tags/Android-IPC/" style="font-size: 10px;">Android-IPC</a> <a href="/tags/Binder/" style="font-size: 16px;">Binder</a> <a href="/tags/DiskLruCache/" style="font-size: 10px;">DiskLruCache</a> <a href="/tags/Fragment/" style="font-size: 10px;">Fragment</a> <a href="/tags/HTTP/" style="font-size: 20px;">HTTP</a> <a href="/tags/Java/" style="font-size: 10px;">Java</a> <a href="/tags/Notification/" style="font-size: 10px;">Notification</a> <a href="/tags/RemoteView/" style="font-size: 10px;">RemoteView</a> <a href="/tags/Rxjava/" style="font-size: 14px;">Rxjava</a> <a href="/tags/ServiceManager/" style="font-size: 14px;">ServiceManager</a> <a href="/tags/android/" style="font-size: 12px;">android</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/java/" style="font-size: 18px;">java</a> <a href="/tags/other/" style="font-size: 10px;">other</a> <a href="/tags/volley/" style="font-size: 12px;">volley</a> <a href="/tags/widget/" style="font-size: 10px;">widget</a> <a href="/tags/事件/" style="font-size: 10px;">事件</a> <a href="/tags/组件化/" style="font-size: 10px;">组件化</a> <a href="/tags/设计模式/" style="font-size: 18px;">设计模式</a>
        </div>
    </div>
    <a href="javascript:;" class="sidebar-menu-box-close">&times;</a>
</div>
<div class="mobile-header-menu-nav" id="mobile-header-menu-nav">
    <div id="mobile-header-menu-container">
        <span class="title">Menu</span>
        <ul class="mobile-header-menu-navbar">
            
            <li>
                <a  href="/">
                    <i class="fa fa-home"></i><span>Home</span>
                </a>
            </li>
            
            <li>
                <a  href="/archives">
                    <i class="fa fa-archive"></i><span>Archives</span>
                </a>
            </li>
            
            <li>
                <a  href="/about">
                    <i class="fa fa-user"></i><span>About</span>
                </a>
            </li>
            
        </ul>
    </div>
</div>
<div class="search-wrap">
    <span class="search-close">&times;</span>
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
            <i class="icon icon-lg icon-chevron-left"></i>
        </a>
        <input class="search-field" placeholder="Search..." id="keywords">
        <a id="search-submit" href="javascript:;">
            <i class="fa fa-search"></i>
        </a>
    <div class="search-container" id="search-container">
        <ul class="search-result" id="search-result">
        </ul>
    </div>
</div>

<div id="search-tpl">
    <li class="search-result-item">
        <a href="{url}" class="search-item-li">
            <span class="search-item-li-title" title="{title}">{title}</span>
        </a>
    </li>
</div>
<script src="/js/search.js"></script>
<script src="/js/main.js"></script>








  </div>
</body>
</html>